using System;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;

namespace FileUtility.FTP.FTP
{
	/// <summary>
	/// The purpose of this class is to provide information necessary to maintaining 
	/// state when using call backs.
	/// </summary>
	/// <remarks>
	/// Programmer:			Edmond Woychowsky
	/// Creation Date:		September 10, 2004
	/// Last Modification:	
	/// </remarks>
	public class StateMaintenance 
	{
		#region constants
		protected const string CRLF = "\r\n";		//	Carriage return/line feed
		#endregion

		#region static
		private static int buffer_size = 4096;		//	Buffer size
		#endregion

		#region private
		private Socket m_socket = null;				//	Command/data socket
		private AsyncCallback m_callback;			//	Callback method
		private StringBuilder m_response = new StringBuilder();
		private string m_commandString = null;		//	FTP command
		private int m_returncode;					//	Command return code
		private byte[] m_commandBytes;				//	FTP command byte array
		private byte[] m_buffer = new byte[buffer_size];
		#endregion

		#region publicProperties
		/// <summary>
		/// The purpose of this property is to get/set the current System.Net.Sockets 
		/// Socket instance.
		/// </summary>
		public Socket socket 
		{
			get 
			{
				return(this.m_socket);
			}
			set 
			{
				this.m_socket = (Socket)value;
			}
		}

		/// <summary>
		/// The purpose of this property is to get/set the asynchronous callback.
		/// </summary>
		public AsyncCallback callback 
		{
			get 
			{
				return(this.m_callback);
			}
			set 
			{
				this.m_callback = (AsyncCallback)value;
			}
		}

		/// <summary>
		/// The purpose of this property is to get/set the buffer.
		/// </summary>
		public byte[] buffer 
		{
			get 
			{
				return(this.m_buffer);
			}
			set 
			{
				this.m_buffer = (byte[])value;
			}
		}
		
		/// <summary>
		/// The purpose of this property is to get the default size of buffers.
		/// </summary>
		public int BUFFER_SIZE 
		{
			get 
			{
				return(buffer_size);
			}
		}

		/// <summary>
		/// The purpose of this property is to get/or set the current command being 
		/// executed.
		/// </summary>
		public string command 
		{
			get 
			{
				return(this.m_commandString);
			}
			set 
			{
				Regex re = new Regex(@"\s{2,}");
				StringBuilder command = new StringBuilder();
				string work = re.Replace(value.ToString()," ");

				re = new Regex(@"\s{1,}$");

				command.Append(re.Replace(work,""));
				command.Append(CRLF);

				this.m_commandString = command.ToString();
				this.m_commandBytes = Encoding.ASCII.GetBytes(this.m_commandString);
			}
		}

		/// <summary>
		/// The purpose of this property is to get a byte array consisting of the current 
		/// command.
		/// </summary>
		public byte[] bytes 
		{
			get 
			{
				return(this.m_commandBytes);
			}
		}

		/// <summary>
		/// The purpose of this property is to get the response buffer.
		/// </summary>
		public string response 
		{
			get 
			{
				return(this.m_response.ToString());
			}
			set 
			{
				this.m_response.Append(value.ToString());

				try 
				{
					this.m_returncode = int.Parse(this.m_response.ToString().Substring(0,3));
				}
				catch(Exception) { }
			}
		}

		/// <summary>
		/// The purpose of this property is to get/set the return code.
		/// </summary>
		public int returncode 
		{
			get 
			{
				return(this.m_returncode);
			}
			set 
			{
				this.m_returncode = int.Parse(value.ToString());
			}
		}
		#endregion

		#region publicMethods
		/// <summary>
		/// The purpose of this method is to reset the response string to null.
		/// </summary>
		public void reset() 
		{
			this.m_response = new StringBuilder();
		}

		/// <summary>
		/// The purpose of this method is to close the socket.
		/// </summary>
		public void close() 
		{
			this.m_socket.Close();
		}

		/// <summary>
		/// The purpose of this method is to format an error message for the current 
		/// command.
		/// </summary>
		/// <returns>Formatted error message</returns>
		public string error() 
		{
			Regex re = new Regex(@"\r\n");			//	Regular expression
			StringBuilder message = new StringBuilder();

			message.Append("FTP ");
			message.Append(re.Replace(this.m_commandString,""));
			message.Append(" command failed");

			return(message.ToString());
		}
		#endregion
	}
}
